﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace SCG.TurboSprite
{
    [ToolboxBitmap(typeof(SpriteSurfaceNavigator), "SpriteSurfaceNavigator")]
    public partial class SpriteSurfaceNavigator : Control
    {
        //constructors
        public SpriteSurfaceNavigator()
        {
            InitializeComponent();
        }
        public SpriteSurfaceNavigator(IContainer container)
        {
            container.Add(this);
            InitializeComponent();
        }

        //Events
        public event EventHandler<PaintEventArgs> CustomPaint;

        //SpriteSurface that this view is navigating
        public SpriteSurface SpriteSurface
        {
            get
            {
                return _surface;
            }
            set
            {
                if (_surface != null)
                    _surface.OffsetChanged -= OffsetChanged;
                _surface = value;
                if (_surface != null)
                    _surface.OffsetChanged += OffsetChanged;
            }
        }

        //Access size multiples
        public float XMult
        {
            get
            {
                return _xMult;
            }
        }
        public float YMult
        {
            get
            {
                return _yMult;
            }
        }

        //Access properties about the viewport frame
        public Color FrameColor
        {
            get
            {
                return _frameColor;
            }
            set
            {
                _frameColor = value;
            }
        }
        public int FrameWidth
        {
            get
            {
                return _frameWidth;
            }
            set
            {
                _frameWidth = value;
            }
        }

        //Should the border be visible?
        public bool BorderVisible
        {
            get
            {
                return _borderVisible;
            }
            set
            {
                _borderVisible = value;
                Invalidate();
            }
        }

        //Border color
        public Color BorderColor
        {
            get
            {
                return _borderColor;
            }
            set
            {
                _borderColor = value;
                Invalidate();
            }
        }

        //Border width
        public int BorderWidth
        {
            get
            {
                return _borderWidth;
            }
            set
            {
                _borderWidth = value;
                Invalidate();
            }
        }


        //private members
        private float _xMult = 0;
        private float _yMult = 0;
        private SpriteSurface _surface;
        private Color _frameColor = Color.Red;
        private int _frameWidth = 1;
        private bool _scrolling = false;
        private bool _borderVisible = true;
        private Color _borderColor = Color.Aqua;
        private int _borderWidth = 1;

        //don't paint background
        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            if (DesignMode)
                base.OnPaintBackground(pevent);
        }

        //Render the navigation view
        protected override void OnPaint(PaintEventArgs e)
        {
            if (DesignMode || SpriteSurface == null)
            {
                base.OnPaint(e);
                return;
            }

            //Calculate multiples            
            _xMult = (float)Width / (float)SpriteSurface.VirtualWidth;
            _yMult = (float)Height / (float)SpriteSurface.VirtualHeight;

            //Fill with background color
            e.Graphics.Clear(BackColor);

            //Allow derived classes their hook here
            OnCustomPaint(e);

            //Allow event handler to draw
            if (CustomPaint != null)
                CustomPaint(this, e);

            //Draw the frame around visible viewport
            float x = SpriteSurface.OffsetX * _xMult;
            float y = SpriteSurface.OffsetY * _yMult;
            float w = SpriteSurface.Width * _xMult;
            float h = SpriteSurface.Height * _yMult;
            Pen p = new Pen(FrameColor, FrameWidth);
            using(p)
            {
                e.Graphics.DrawRectangle(p, x, y, w, h);
            }

            //Draw the border
            if (BorderVisible)
            {
                Pen borderPen = new Pen(_borderColor, _borderWidth);
                using (borderPen)
                {
                    e.Graphics.DrawRectangle(borderPen, new Rectangle(0, 0, Width, Height));
                }
            }
        }

        //Hook for derived classes to render the navigation display
        protected virtual void OnCustomPaint(PaintEventArgs e)
        {
        }

        //Scrolling
        protected override void OnMouseDown(MouseEventArgs e)
        {
            _scrolling = true;
            base.OnMouseDown(e);
        }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (_scrolling)
                Scroll(e);
            base.OnMouseMove(e);
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            Scroll(e);
            _scrolling = false;
            base.OnMouseUp(e);
        }
        private void Scroll(MouseEventArgs e)
        {
            //determine point clicked in the SpriteSurface
            float xm = (float)SpriteSurface.VirtualWidth / (float)Width;
            float ym = (float)SpriteSurface.VirtualHeight / (float)Height;
            float x = e.X * xm;
            float y = e.Y * ym;
            SpriteSurface.CenterOn((int)x, (int)y);         
        }

        //event handler for responding to offset changes
        private void OffsetChanged(object sender, EventArgs e)
        {
            Invalidate();
        }
    }
}
